package cc.zy.base.businesses.utils;

import cc.zy.base.common.entity.ModuleType;
import cc.zy.base.common.entity.OssProperties;
import cc.zy.base.common.utils.OssUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.LinkedHashMap;

@Slf4j
@Configuration
@EnableConfigurationProperties(OssProperties.class)
public class SignFileUtil {

    @Autowired
    private static OssProperties ossProperties;

    @Autowired
    public SignFileUtil(OssProperties ossProperties) {
        this.ossProperties = ossProperties;
    }

//    public static void main(String[] args) {
//        try {
//            File zipFile = File.createTempFile("电子签章", ".pdf");
//            String filePath = zipFile.getPath();
//            log.debug(String.format("zipFile = %1$s", filePath));
//            downloadFile("https://oss.esign.cn/1111563786/f846c3aa-b820-425c-af20-58b0d46e0835/%E6%8A%A5%E8%80%83%E5%8D%8F%E8%AE%AE-%E5%BA%94%E7%94%A8%E5%9E%8B%E8%87%AA%E5%AD%A6%E8%80%83%E8%AF%95%EF%BC%88%E8%A5%BF%E5%AE%89%EF%BC%89.pdf?Expires=1630495433&OSSAccessKeyId=LTAI4G5MrNNRU1tH6qtY4Moi&Signature=RMl1tOB13%2B%2Fxmt4E1wWW1RT%2FbdU%3D",filePath);
//            log.debug(String.format("zipFileName = %1$s", zipFile.getName()));
//            String ossFilePath = uploadBill(filePath, zipFile.getName());
//            log.debug(String.format("ossFilePath = %1$s", ossFilePath));
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }






    /**
     * TODO 下载文件到本地
     * @author nadim
     * @date Sep 11, 2015 11:45:31 AM
     * @param fileUrl 远程地址
     * @param fileLocal 本地路径
     * @throws Exception
     */
    public static void downloadFile(String fileUrl,String fileLocal) throws Exception {
        URL url = new URL(fileUrl);
        HttpURLConnection urlCon = (HttpURLConnection) url.openConnection();
        urlCon.setConnectTimeout(6000);
        urlCon.setReadTimeout(6000);
        int code = urlCon.getResponseCode();
        if (code != HttpURLConnection.HTTP_OK) {
            throw new Exception("文件读取失败");
        }

        //读文件流
        DataInputStream in = new DataInputStream(urlCon.getInputStream());
        DataOutputStream out = new DataOutputStream(new FileOutputStream(fileLocal));
        byte[] buffer = new byte[2048];
        int count = 0;
        while ((count = in.read(buffer)) > 0) {
            out.write(buffer, 0, count);
        }
        out.close();
        in.close();
    }

    public static String uploadBill(String str, String fileName) throws Exception{

        log.info("正在上传文件");

//        log.info(String.format("strBegin = %s", str));
//        String s = str.replaceAll("\\\\","/");
//        log.info(String.format("s = %s", s));

        File file = new File(str);
        log.info(String.format("file = %s", file));
        String uploadUrl= null;

        try {
            uploadUrl = OssUtil.uploadBill(file,ossProperties, ModuleType.SIGNATURE_FILE.getPath(), fileName);
            log.info(String.format("uploadUrl = %s",uploadUrl));
        } catch (Exception e) {
            log.error(String.format("OSS上传异常 = %s", e));
            return "文件上传失败";
        }

        if (uploadUrl != null){
            if (file.exists() && file.isFile()) {
                if (file.delete()) {
                    log.debug("删除单个文件" + fileName + "成功！");
                } else {
                    log.debug("删除单个文件" + fileName + "失败！");
                }
            } else {
                log.debug("删除单个文件失败：" + fileName + "不存在！");
            }
        }

        return uploadUrl;
    }

    /***
     * 请求签名鉴权-GET请求
     *
     * @param flowId
     * @param appKey
     * @param appId
     */
    public static String getFlowFile(String flowId, String host, String appKey, String appId) {
        // 查询个人印章接口
        String getPersonSealsApi = "/v1/signflows/" + flowId + "/documents";
        // 查询个人印章接口请求地址
        String getPersonSealsApi_Url = host + getPersonSealsApi;

        try {
            // GET请求时ContentMD5为""
            String contentMD5 = "{}";

            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = getPersonSealsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, appKey);

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", appId);
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendGet(getPersonSealsApi_Url, header, "UTF-8");
            JSONObject resultObj = JSONObject.fromObject(result);
            System.out.println("请求返回信息： " + resultObj.toString());
            System.out.println("签署完成后文档地址为： " + resultObj.getJSONObject("data").getJSONArray("docs").getJSONObject(0).getString("fileUrl"));
            return resultObj.getJSONObject("data").getJSONArray("docs").getJSONObject(0).getString("fileUrl");
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }
    }

    /***
     * 计算请求签名值
     *
     * @param message 待计算的消息
     * @param secret 密钥
     * @return HmacSHA256计算后摘要值的Base64编码
     * @throws Exception 加密过程中的异常信息
     */
    public static String doSignatureBase64(String message, String secret) throws Exception {
        String algorithm = "HmacSHA256";
        Mac hmacSha256;
        String digestBase64 = null;
        try {
            hmacSha256 = Mac.getInstance(algorithm);
            byte[] keyBytes = secret.getBytes("UTF-8");
            byte[] messageBytes = message.getBytes("UTF-8");
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
            // 使用HmacSHA256对二进制数据消息Bytes计算摘要
            byte[] digestBytes = hmacSha256.doFinal(messageBytes);
            // 把摘要后的结果digestBytes转换成十六进制的字符串
            // String digestBase64 = Hex.encodeHexString(digestBytes);
            // 把摘要后的结果digestBytes使用Base64进行编码
            digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (InvalidKeyException e) {
            String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return digestBase64;
    }

    /***
     * 获取时间戳(毫秒级)
     *
     * @return 毫秒级时间戳,如 1578446909000
     */
    public static long timeStamp() {
        long timeStamp = System.currentTimeMillis();
        return timeStamp;
    }

}
